package com.blue.waffle.iwc.screens;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
import com.blue.waffle.iwc.domains.Difficulties;
import com.blue.waffle.iwc.domains.Difficulty;
import com.blue.waffle.iwc.domains.Level;
import com.blue.waffle.iwc.domains.Profile;
import com.blue.waffle.iwc.domains.Word;
import com.blue.waffle.iwc.game.IWCGame;
import com.blue.waffle.iwc.ui.Blank;
import com.blue.waffle.iwc.ui.ButtonActorListener;
import com.blue.waffle.iwc.ui.GameMenuDialog;
import com.blue.waffle.iwc.ui.Letter;
import com.blue.waffle.iwc.ui.MessageDialog;

public class GameScreen extends AbstractScreen {

	private Difficulty difficulty;
	private Level level;
	private Word word;
	private TextureAtlas gameTextureAtlas;
	private TextureRegion[] letterFrames;
	private float totalPlayedTime;
	private LetterGameListener letterGameListener;
	private Label timerLabel;
	private Label attemptLabel;
	private Label difficultyLabel;
	private TextButton hintBtn;
	private TextButton menuBtn;
	private int timeLimit;
	private int attempts;
	private List<Blank> blanks;
	private List<Letter> lettersToDrag;
	private Difficulties difficultyRules;
	private boolean stop;
	private long score;

	public Level getLevel() {
		return level;
	}
	
	public int getTimeLimit() {
		return timeLimit;
	}
	
	public GameScreen(IWCGame game, Difficulty difficulty) {
		super(game);
		this.difficulty = difficulty;
	}

	@Override
	public void show() {
		super.show();
		
		//Profile userProfile = game.getGameManager().getUserProfile();
		level = game.getGameManager().getNextLevel();

		word = game.getGameManager().getLevelWord(level);
		
		difficultyRules=game.getGameManager().getDifficultyRules();
		
		System.out.println(word.getWord());

		Rectangle.tmp.set(0, 0, IWCGame.VIRTUAL_WIDTH, IWCGame.VIRTUAL_HEIGHT);
		TextureRegion alphabetRegion = getGameTextureAtlas().findRegion(
				"letterSprite");
		Texture alphabetTexture = alphabetRegion.getTexture();
		TextureRegion[][] tmp = TextureRegion.split(alphabetTexture,
				alphabetRegion.getRegionWidth() / 7,
				alphabetRegion.getRegionHeight() / 4);
		letterFrames = new TextureRegion[7 * 4];
		int index = 0;
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 7; j++) {
				letterFrames[index++] = tmp[i][j];
			}
		}
		
		drawGameMenu();
		drawLettersAndBlanks();

	}
	
	@Override
	public void render(float delta) {
		if (!stop) {
			totalPlayedTime += delta;

			if (difficultyRules.isShowTimer()) {
				checkTimer();
			}
		}

		super.render(delta);
		checkGameOver();
	}
	
	public Difficulties getDifficultyRules() {
		return difficultyRules;
	}
	
	private void checkGameOver(){
		
		if (letterGameListener.isFinished()&&!letterGameListener.isOver()) {
			if (letterGameListener.isCleared()) {
				letterGameListener.setOver(true);
				stop=true;
				level.setCompleted(true);
				level.setPlayTime((int)totalPlayedTime);
				level.setScore(difficultyRules.calculateScore(totalPlayedTime, word.getWord().length()));
				game.getGameManager().addUserLevel(level);
				GameMenuDialog clearedDialog=new GameMenuDialog("Cleared!", getUiSkin(), this, GameMenuDialog.TYPE_LEVEL_CLEARED);
				clearedDialog.show(gameStage);
			}else {
				letterGameListener.reset();
			}
		}
		
	}
	
	private void checkTimer() {
		int timeRemaining = (int)(timeLimit-totalPlayedTime);
		if (timeRemaining<1 && !letterGameListener.isOver()) {
			timerLabel.setText("Time: 0");
			if (!letterGameListener.isFinished()||!letterGameListener.isCleared()) {
				letterGameListener.setOver(true);
				
				GameMenuDialog gameOverDialog=new GameMenuDialog("Time is up", getUiSkin(), this, GameMenuDialog.TYPE_GAMEOVER);
				gameOverDialog.show(gameStage);
			}
		}else if(timeRemaining>=0){
			timerLabel.setText("Time: "+timeRemaining);
		}
		
		
	}
	
	private void drawGameMenu() {
		
		timeLimit=difficultyRules.getTimeLimit();
		if (difficultyRules.isShowTimer()) {
			timerLabel=new Label("Time: "+timeLimit, getUiSkin());
			attempts=difficultyRules.getAttempts();
			attemptLabel=new Label("Attempts: "+attempts,getUiSkin());
		}else {
			timerLabel=new Label("Time: --",getUiSkin());
		}
		difficultyLabel=new Label("Difficulty: "+difficulty.getName(),getUiSkin());
		
		timerLabel.pack();
		timerLabel.setPosition(IWCGame.VIRTUAL_WIDTH/2-timerLabel.getWidth(), IWCGame.VIRTUAL_HEIGHT-timerLabel.getHeight());
		gameStage.addActor(timerLabel);
		
		if (attemptLabel!=null) {
			attemptLabel.pack();
			attemptLabel.setPosition(timerLabel.getRight()+50,timerLabel.getY());
			gameStage.addActor(attemptLabel);
		}
		
		difficultyLabel.pack();
		difficultyLabel.setPosition(IWCGame.VIRTUAL_WIDTH-50-difficultyLabel.getWidth(),difficultyLabel.getHeight());
		gameStage.addActor(difficultyLabel);
		
		hintBtn= new TextButton("Hint", getUiSkin());
		hintBtn.padLeft(10).padRight(10).pack();
		hintBtn.setPosition(WINDOW_PADDINGS, IWCGame.VIRTUAL_HEIGHT-hintBtn.getHeight());
		hintBtn.addListener(new ButtonActorListener(this, word.getDefinition()){
			@Override
			public void clicked(InputEvent event, float x, float y) {
			
				super.clicked(event, x, y);
				MessageDialog hintDialog=new MessageDialog((String)getData(), "Hint", screen.getUiSkin(),MessageDialog.BTN_OK,
						new ButtonActorListener(screen){
							public void clicked(InputEvent event, float x, float y) {
								super.clicked(event, x, y);
							};
						}
				);
				hintDialog.setWidth(IWCGame.VIRTUAL_WIDTH/2);
				hintDialog.show(screen.getGameStage());
			}
		});
		
		if (!difficultyRules.isShowDefinition()) {
			hintBtn.getColor().a=0.5f;
			hintBtn.setTouchable(Touchable.disabled);
		}
		
		menuBtn=new TextButton("Menu", getUiSkin());
		menuBtn.padLeft(10).padRight(10).pack();
		menuBtn.setPosition(IWCGame.VIRTUAL_WIDTH-WINDOW_PADDINGS-menuBtn.getWidth(), IWCGame.VIRTUAL_HEIGHT-menuBtn.getHeight());
		menuBtn.addListener(new ButtonActorListener(this, word.getDefinition()){
			@Override
			public void clicked(InputEvent event, float x, float y) {
			
				super.clicked(event, x, y);
				setStop(true);
				GameMenuDialog menuDialog=new GameMenuDialog("Menu", screen.getUiSkin(), (GameScreen) screen,GameMenuDialog.TYPE_MENU);
				menuDialog.show(screen.getGameStage());
			}
		});
		gameStage.addActor(hintBtn);
		gameStage.addActor(menuBtn);
		
	}

	private void drawLettersAndBlanks() {
		// list to shuffle the char array
		List<Character> chars = new ArrayList<Character>();
		blanks = new ArrayList<Blank>();
		lettersToDrag = new ArrayList<Letter>();
		String wordString=word.getWord();
		int wordLength = wordString.length();
		int frameWidth = letterFrames[0].getRegionWidth();
		
		letterGameListener = new LetterGameListener(blanks,lettersToDrag,difficultyRules);
		
		int startX = IWCGame.VIRTUAL_WIDTH/2 - (wordLength * frameWidth * 2)/2 + frameWidth/2;
		
		for (int i = 0; i < wordLength; i++) {
			char c = wordString.charAt(i);
			chars.add(c);
			Blank b = new Blank(startX+frameWidth * i * 2, IWCGame.VIRTUAL_HEIGHT/2, letterFrames[26], i, c);
			blanks.add(b);
			gameStage.addActor(b);
		}

		Collections.shuffle(chars, new Random(System.currentTimeMillis()));
		for (int i = 0; i < wordLength; i++) {
			char c = chars.get(i);
			Letter letter = new Letter(startX+frameWidth * i * 2, IWCGame.VIRTUAL_HEIGHT/2 +100,
					letterFrames[c - 'a'], c - 'a', c);
			lettersToDrag.add(letter);
			letter.addListener(letterGameListener);
			gameStage.addActor(letter);
		}
	}

	public TextureAtlas getGameTextureAtlas() {
		if (gameTextureAtlas == null) {
			gameTextureAtlas = game.getAssetManager().get(
					"game-images/game-images.atlas", TextureAtlas.class);
		}
		return gameTextureAtlas;
	}

	@Override
	public void dispose() {

		super.dispose();
		if (gameTextureAtlas != null) {
			gameTextureAtlas.dispose();
		}
	}

	public boolean isStop() {
		return stop;
	}

	public void setStop(boolean stop) {
		this.stop = stop;
	}
	
	public void useAttempt() {
		this.attempts --;
		letterGameListener.reset();
		totalPlayedTime=0;
		stop=false;
		attemptLabel.setText("Attempts: "+attempts);
	}
	
	public int getAttempts() {
		return attempts;
	}

	public long getScore() {
		return score;
	}

	public void setScore(long score) {
		this.score = score;
	}

	private static class LetterGameListener extends ActorGestureListener {
		private List<Blank> blanks;
		private Difficulties difficulty;
		private boolean finished;
		private boolean cleared;
		private List<Letter>letters;
		private boolean over;
		
		public void reset(){
			over=false;
			Blank.reset(blanks);
			Letter.reset(letters);
		}
		
		public LetterGameListener(List<Blank> blanks,List<Letter> letters,Difficulties difficulty) {
			this.blanks = blanks;
			this.difficulty=difficulty;
			this.letters=letters;
		}
		
		private boolean checkFinished() {
			for (Blank blank : blanks) {
				finished=!blank.isEmpty();
				if (!finished) {
					break;
				}
			}
			return finished;
		}
		
		private boolean checkLevelCleared(){
			for (Blank blank: blanks) {
				cleared=blank.isCorrect();
				if (!cleared) {
					break;
				}
			}
			return cleared;
		}
		
		
		public boolean isCleared() {
			return cleared;
		}
		
		public boolean isFinished() {
			return finished;
		}

		@Override
		public void pan(InputEvent event, float x, float y, float deltaX,
				float deltaY) {
			if (!over) {
				float actorX = event.getTarget().getX() + deltaX;
				float actorY = event.getTarget().getY() + deltaY;
				Rectangle.tmp2.set(actorX, actorY, event.getTarget().getWidth(),
						event.getTarget().getHeight());
				Rectangle.tmp.set(0, 0, IWCGame.VIRTUAL_WIDTH, IWCGame.VIRTUAL_HEIGHT);
				if (Rectangle.tmp.contains(Rectangle.tmp2)) {
					event.getTarget().setPosition(actorX, actorY);
				}
			}
			
		}

		@Override
		public void touchUp(InputEvent event, float x, float y, int pointer,
				int button) {
			if (!over) {
				Letter letter = (Letter) event.getTarget();
				Blank filledBlank=null;
				for (Blank b : blanks) {
					int currentBlankIndex=blanks.indexOf(b);
					//checks if the current selected letter is filled to an empty blank
					if (new Rectangle(b.getBlankRect().x - 15,
							b.getBlankRect().y - 15,
							event.getTarget().getWidth() + 15, event.getTarget()
									.getHeight() + 15).contains(event.getTarget()
							.getX(), event.getTarget().getY()) && b.isEmpty()){
						
						//always fill the blank
						b.setEmpty(false);
						letter.setPosition(b.getBlankRect().x, b.getBlankRect().y);
						//always set the filled letter to the blank
						b.setFilledLetter(letter.getLetter());
						
						//get the last filled blank from the letter
						int lastFilledBlankIndex=letter.getFilledBlankIndex();
						
						Blank lastFilledBlank=null;
						//only reset the last blank if it has filled one before
						//and the last filled blank index is greater than the current blank index
						//because we want to break the loop from here
						if (lastFilledBlankIndex!=-1 && currentBlankIndex<lastFilledBlankIndex) {
							lastFilledBlank=blanks.get(lastFilledBlankIndex);
							lastFilledBlank.setEmpty(true);
						}
						//update the filled blank index
						letter.setFilledBlankIndex(currentBlankIndex);
						filledBlank=b;
						break;
					}else {
						//only reset the filled blank if it matches the one from the letter
						if (letter.getFilledBlankIndex()==currentBlankIndex) {
							b.setEmpty(true);
							letter.setFilledBlankIndex(-1);
						}
					}
				}
				
				//always perform a check if the level is all the blanks are filled
				//and if the level is cleared
				if (checkFinished()) {
					checkLevelCleared();
				}

				//reset the letter position if the filled blank is null (non-easy difficulty)
				//or the filled letter is not correct (easy difficulty only)
				if (filledBlank==null || difficulty.isValidate()&& !filledBlank.isCorrect()) {
					letter.setPosition(letter.getOriginalPosition().x,
							letter.getOriginalPosition().y);
					letter.setSelected(false);
					if (filledBlank!=null && !filledBlank.isEmpty()) {
						filledBlank.setEmpty(true);
					}
					letter.setFilledBlankIndex(-1);
				}else {
					return;
				}
			}
		}
		
		@Override
		public void touchDown(InputEvent event, float x, float y, int pointer,
				int button) {
			if (!over) {
				event.getTarget().toFront();
				super.touchDown(event, x, y, pointer, button);
			}
			
		}

		public boolean isOver() {
			return over;
		}

		public void setOver(boolean over) {
			this.over = over;
		}

		
	}

}
